package com.atguigu.gmall.cart.service;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private CartInfoSyncService cartInfoSyncService;
    @Autowired
    private CartInfoMapper cartInfoMapper;

    //加入购物车时 加入购物车
    @Override
    public void addToCart(Long skuId, Integer skuNum, String userId) {
        System.out.println("主线程名" + Thread.currentThread().getName());
        //(重要) 保存到Redis中
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
        if (null != cartInfo) {
            //此用户在之前已加入过此商品 本次追加数量
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            //异步更新数据
            cartInfoSyncService.updateCartInfo(cartInfo);
        } else {
            //此用户在之前没加入过此商品
            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuNum(skuNum);
            //实际两次远程调用需要写成一次查询DB 而不是查询缓存
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            //实时价格
            BigDecimal price = productFeignClient.getPrice(skuId);
            cartInfo.setCartPrice(price);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            //(不重要) 保存到DB中 需要异步
            cartInfoSyncService.insertCartInfo(cartInfo);//异步
        }
        cartInfo.setIsChecked(1);
        redisTemplate.opsForHash().put(cartHKey, skuId.toString(), cartInfo);
    }

    //加入购物车时 查询购物车
    @Override
    public CartInfo toCart(Long sId) {
        //任意位置获取对象
        String userId = getUserId();
        System.out.println("userId is " + userId);
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        return (CartInfo) redisTemplate.opsForHash().get(cartHKey, sId.toString());
    }

    //获取userId
    private String getUserId() {
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)) {
            userId = AuthContextHolder.getUserTempId(request);
        }
        return userId;
    }

    //查询购物车集合
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //1.用户是否登录?
        if (!StringUtils.isEmpty(userId)) {
            //登录了 有真实用户id
            if (!StringUtils.isEmpty(userTempId)) {
                //有真实用户id 也有临时用户id 重点!!!
                //合并
                return mergeCartInfoList(userId, userTempId);
            } else {
                //有真实用户id 但无临时用户id 无需合并
                return getCartInfoList(userId);
            }
        } else {
            //未登录 有临时用户
            if (!StringUtils.isEmpty(userTempId)) {
                //直接返回临时用户购物车
                return getCartInfoList(userTempId);
            } else {
                //未登录 没有临时用户  临时用户只有在添加购物车产生,若不登录直接点购物车则不会产生临时用户,此时购物车为空
                return null;
            }
        }
    }

    //大合并 合并真实用户购物车和临时用户购物车 真实用户和临时用户从HttpServletRequest各能获取一个
    private List<CartInfo> mergeCartInfoList(String userId, String userTempId) {
        //1.获取购物车集合(真实用户)
        List<CartInfo> cartInfoListByUserId = getCartInfoList(userId);
        //2.获取购物车集合(临时用户)
        List<CartInfo> cartInfoListByUserTempId = getCartInfoList(userTempId);
        //3.开始合并
        if (!CollectionUtils.isEmpty(cartInfoListByUserId)) {
            //真实用户有购物车
            if (!CollectionUtils.isEmpty(cartInfoListByUserTempId)) {
                //真实用户有购物车 临时用户有购物车
                //真正的合并
                //Map K:skuId V:CartInfo
                Map<String, CartInfo> mapByUserId = cartInfoListByUserId.stream().collect(Collectors.toMap(
                        cartInfo -> cartInfo.getSkuId().toString(),
                        cartInfo -> cartInfo
                ));
                //3.1遍历临时购物车集合
                for (CartInfo cartInfoByUserTempId : cartInfoListByUserTempId) {
                    CartInfo cartInfoByUserId = mapByUserId.get(cartInfoByUserTempId.getSkuId().toString());
                    if (null != cartInfoByUserId) {
                        //3.2相同商品追加数量
                        cartInfoByUserId.setSkuNum(cartInfoByUserId.getSkuNum() + cartInfoByUserTempId.getSkuNum());
                        cartInfoByUserId.setIsChecked(1);
                    } else {
                        //3.3不同商品添加新品
                        cartInfoByUserTempId.setUserId(userId);
                        mapByUserId.put(cartInfoByUserTempId.getSkuId().toString(), cartInfoByUserTempId);
                    }
                }
                ArrayList<CartInfo> cartInfoList = new ArrayList<>(mapByUserId.values());
                //TODO 异步
                //统一处理DB 删除真实用户id+临时用户id  in的第二个参数是可变长形参
                cartInfoMapper.delete(new QueryWrapper<CartInfo>().in("user_id", userId, userTempId));
                //统一将最新购物车集合 添加(批量)
                this.saveBatch(cartInfoList);
                //统一删除Redis中临时用户的hash
                String cartHKeyByTempId = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
                redisTemplate.delete(cartHKeyByTempId);
                //统一更新Redis中真实用户的hash
                String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
                //相同
                redisTemplate.opsForHash().putAll(cartHKey, mapByUserId);
//                return (List<CartInfo>) mapByUserId.values();//错误
                return cartInfoList;//正确
            } else {
                //真实用户有购物车 临时用户没有购物车
                return cartInfoListByUserId;
            }
        } else {
            //真实用户没有购物车 返回临时用户购物车->可能为空
            return cartInfoListByUserTempId;
        }
    }

    //获取购物车集合 根据用户id
    private List<CartInfo> getCartInfoList(String userId) {
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartHKey);
//        cartInfoList.forEach(cartInfo -> {
//            //要求查询DB的实时价格
//            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
//            cartInfo.setSkuPrice(price);
//        });
//        //前减后 升序
//        cartInfoList = cartInfoList.stream().sorted((cartInfo1, cartInfo2) -> {
//            return cartInfo2.getSkuPrice().intValue() - cartInfo1.getSkuPrice().intValue();
//        }).collect(Collectors.toList());
//        return cartInfoList;
        return cartInfoList.stream().peek(cartInfo -> {
            //要求查询DB的实时价格
            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(price);
        }).sorted((cartInfo1, cartInfo2) -> {
            return cartInfo2.getSkuPrice().intValue() - cartInfo1.getSkuPrice().intValue();
        }).collect(Collectors.toList());
    }

    //更新选中状态
    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        String userId = getUserId();
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //更新Redis
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cartHKey, skuId.toString());
        cartInfo.setIsChecked(isChecked);
        redisTemplate.opsForHash().put(cartHKey, skuId.toString(), cartInfo);
        //异步更新DB
        cartInfoSyncService.updateCartInfo(cartInfo);
    }

    //删除单个购物车
    @Override
    public void deleteCart(Long skuId) {
        String userId = getUserId();
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //更新Redis
        redisTemplate.opsForHash().delete(cartHKey, skuId.toString());
        //异步更新DB
        cartInfoSyncService.deleteCartInfo(userId, skuId);
    }

    //商品清单
    @Override
    public List<CartInfo> getCartInfoListByChecked(String userId) {
        String cartHKey = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        //查全部 只能先查全部再处理
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cartHKey);
        //先过滤
        return cartInfoList.stream().filter(cartInfo -> 1 == cartInfo.getIsChecked()).
                peek(cartInfo -> {
                    //查询实时价格
                    BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
                    cartInfo.setSkuPrice(price);
                }).collect(Collectors.toList());
    }
}
